001    /*
002     * Copyright 2005 Stephen J. McConnell
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.library.impl;
020    
021    import java.util.ArrayList;
022    import java.util.Enumeration;
023    import java.util.Properties;
024    
025    import net.dpml.library.Dictionary;
026    import net.dpml.library.info.AbstractDirective;
027    
028    import net.dpml.util.PropertyResolver;
029    
030    /**
031     * Utility class used for construction of a module model from an XML source.
032     *
033     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
034     * @version 1.1.0
035     */
036    public class DefaultDictionary implements Dictionary
037    {
038        private final DefaultDictionary m_parent;
039        private final AbstractDirective m_directive;
040        private final Properties m_properties;
041        
042       /**
043        * Creation of a new dictionary.  The dictionary provides support
044        * for property inheritance within the hierachy of of modules based
045        * an a single root virtual module.  When handling a propety request
046        * the dictionary will attempt to resolve the property value using 
047        * local property values.  If the value is unresolved, the implemenetation
048        * will attempt to delegate the request to a parent dictionary if available.
049        *
050        * @param parent the parent dictionary (possibly null)
051        * @param directive an abstract directive containing local properties
052        */
053        public DefaultDictionary( DefaultDictionary parent, AbstractDirective directive )
054        {
055            if( null == directive )
056            {
057                throw new NullPointerException( "directive" );
058            }
059            m_parent = parent;
060            m_directive = directive;
061            
062            Properties properties = getParentProperties();
063            m_properties = new Properties( properties );
064            Properties local = directive.getProperties();
065            String[] keys = getLocalPropertyNames( local );
066            for( int i=0; i<keys.length; i++ )
067            {
068                String key = keys[i];
069                String value = local.getProperty( key );
070                m_properties.setProperty( key, value );
071            }
072        }
073        
074        //----------------------------------------------------------------------------
075        // Dictionary
076        //----------------------------------------------------------------------------
077        
078       /**
079        * Return the property names associated with the dictionary.
080        * @return the array of property names
081        */
082        public String[] getPropertyNames()
083        {
084            return getLocalPropertyNames( m_properties );
085        }
086        
087       /**
088        * Return the local property names associated with the dictionary.
089        * @return the array of local property names
090        */
091        public String[] getLocalPropertyNames()
092        {
093            return getLocalPropertyNames( m_directive.getProperties() );
094        }
095        
096       /**
097        * Return a property value.
098        * @param key the property key
099        * @return the property value
100        */
101        public String getProperty( String key )
102        {
103            return getProperty( key, null );
104        }
105        
106       /**
107        * Return a property value.
108        * @param key the property key
109        * @param value the default value
110        * @return the property value
111        */
112        public String getProperty( String key, String value )
113        {
114            String result = m_properties.getProperty( key, value );
115            return resolve( result );
116        }
117        
118       /**
119        * Return an integer property value.
120        * @param key the property key
121        * @param value the default value
122        * @return the property value as an integer
123        */
124        public int getIntegerProperty( String key, int value )
125        {
126            String result = m_properties.getProperty( key );
127            if( null == result )
128            {
129                return value;
130            }
131            else
132            {
133                String literal = resolve( result );
134                return Integer.parseInt( literal );
135            }
136        }
137        
138       /**
139        * Return an boolean property value.
140        * @param key the property key
141        * @param value the default value
142        * @return the property value as an boolean
143        */
144        public boolean getBooleanProperty( String key, boolean value )
145        {
146            String result = m_properties.getProperty( key );
147            if( null != result )
148            {
149                return Boolean.valueOf( result ).booleanValue();
150            }
151            else
152            {
153                return value;
154            }
155        }
156       /**
157        * Evaluate and expand any symbolic references in the supplied value.
158        * @param value the value to resolve
159        * @return the resolved value
160        */
161        public String resolve( String value )
162        {
163            return PropertyResolver.resolve( m_properties, value );
164        }
165        
166        //----------------------------------------------------------------------------
167        // internal
168        //----------------------------------------------------------------------------
169        
170        void setProperty( String name, String value )
171        {
172            m_properties.setProperty( name, value );
173        }
174        
175        AbstractDirective getAbstractDirective()
176        {
177            return m_directive;
178        }
179        
180        Properties getProperties()
181        {
182            return m_properties;
183        }
184        
185        private Properties getParentProperties()
186        {
187            if( null == m_parent )
188            {
189                return new Properties();
190            }
191            else
192            {
193                return m_parent.getProperties();
194            }
195        }
196        
197        private String[] getLocalPropertyNames( Properties properties )
198        {
199            ArrayList list = new ArrayList();
200            Enumeration names = properties.propertyNames();
201            while( names.hasMoreElements() )
202            {
203                list.add( (String) names.nextElement() );
204            }
205            return (String[]) list.toArray( new String[0] );
206        }
207    
208        Properties getExportProperties()
209        {
210            String[] keys = getLocalPropertyNames();
211            Properties properties = new Properties();
212            for( int i=0; i<keys.length; i++ )
213            {
214                String key = keys[i];
215                String value = getProperty( key );
216                properties.setProperty( key, value );
217            }
218            return properties;
219        }
220    }